package com.czmh.etc.onlinepubsys.jy.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @since 2019.05.31 9:38
 */
public class JsonUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);

    private static final ObjectMapper JSON_MAPPER;

    static {
        JSON_MAPPER = new ObjectMapper();
        JSON_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        JSON_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        JSON_MAPPER.setSerializationInclusion(Include.NON_NULL);
    }

    /**
     * 简单类型反序列
     *
     * @param s      待反序列字符串
     * @param tClass 参数类型
     */
    public static <T> T fromJson(String s, Class<T> tClass) {
        try {
            return JSON_MAPPER.readValue(s, tClass);
        } catch (IOException e) {
            LOGGER.error("fromJson fail,oriString [{}]", s, e);
            return null;
        }
    }

    /**
     * javaType 存储
     */
    private Map<String, JavaType> typeMap = new ConcurrentHashMap<>();

    /**
     * 泛型反序列,成功返回对象,失败返回空值
     *
     * @param s                待反序列字符串
     * @param tClass           参数类型
     * @param parameterClasses 泛型参数
     * @return if convert success return object,else return null
     */
    public <T> T fromJson(String s, Class<T> tClass, Class... parameterClasses) {
        // className join with '_' as key
        StringBuilder builder = new StringBuilder(tClass.getName());
        for (Class aClass : parameterClasses) {
            builder.append("_").append(aClass.getName());
        }

        String key = builder.toString();
        JavaType type = typeMap.get(key);

        if (null == type) {
            type = TypeFactory.defaultInstance().constructParametricType(tClass, parameterClasses);
            typeMap.putIfAbsent(key, type);
        }
        type = typeMap.get(key);

        try {
            return JSON_MAPPER.readValue(s, type);
        } catch (IOException e) {
            LOGGER.error("fromJson fail,oriString [{}]", s, e);
            return null;
        }
    }

    /**
     * @param obj 待序列化对象
     */
    public static String toJson(Object obj) {
        try {
            return JSON_MAPPER.writeValueAsString(obj);
        } catch (IOException e) {
            LOGGER.error("toJson fail", e);
            return null;
        }
    }
}
